#!/usr/bin/python3
# -*- coding: utf-8 -*-
'提供python log 功能，log以json方式輸出到文件'
import logging
import socket
import sys
import traceback
from logging import handlers

__author__ = 'Wu shumin'


class LogUtil:
    # # default config for root
    # formatStr = '{"timestamp": "%(asctime)s", "name": "%(name)s", "process": "%(process)d", "processName": "%(processName)s", ' \
    #             '"filename": "%(filename)s", "lineno": "%(lineno)d", "levelname": "%(levelname)s", ' \
    #             '"message": %(message)s}'
    # logging.basicConfig(format=formatStr, datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)
    #
    # #file log for azkaban file
    # formatFile = '{"timestamp": "%(asctime)s", "hostaddr": "%(hostaddr)s", "name": "%(name)s", "process": "%(process)d", "processName": "%(processName)s", ' \
    #             '"pythonfile": "%(pythonfile)s", "line": "%(line)d", "functionname": "%(functionname)s", "levelname": "%(levelname)s", ' \
    #             '"appName": "%(appName)s", "jobName":"%(jobName)s", "message": %(message)s}'
    # logger = logging.getLogger("mars-etl-job-azkaban")
    # log_file = '/data/logs/access/mars-etl-job-azkaban'
    # file_roll_handler = logging.handlers.TimedRotatingFileHandler(filename=log_file, when='M', backupCount=0,
    #                                                           encoding='utf-8')
    # file_roll_handler.suffix = '%Y-%m-%d.log'
    # file_roll_handler.setLevel(logging.INFO)  # error以上的内容输出到文件里面
    # file_roll_handler.setFormatter(logging.Formatter(formatFile))
    # logger.addHandler(file_roll_handler)


    # # 初始化logger，传入客户端的类名，一般为:__name__
    # def __init__(self, appName,jobName):
    #     # 应用名
    #     self.app = appName
    #     # job名称
    #     self.jobName = jobName
    #
    #     # 获取本机电脑名
    #     self.hostname = socket.getfqdn(socket.gethostname())
    #     # 获取本机ip
    #     self.hostip = socket.gethostbyname(self.hostname)

    # 初始化logger，传入客户端的类名，一般为:__name__
    def __init__(self, appName='', jobName='', logger_name='mars-etl-job-azkaban'):
        # 应用名
        self.app = appName
        # job名称
        self.jobName = jobName

        self.logger = logging.getLogger(logger_name)
        # 获取本机电脑名
        self.hostname = socket.getfqdn(socket.gethostname())
        # 获取本机ip
        self.hostip = socket.gethostbyname(self.hostname)

        # default config for root
        formatStr = '{"timestamp": "%(asctime)s", "name": "%(name)s", "process": "%(process)d", "processName": "%(processName)s", ' \
                    '"levelname": "%(levelname)s", ' \
                    '"message": %(message)s}'
        logging.basicConfig(format=formatStr, datefmt="%Y-%m-%d %H:%M:%S", level=logging.INFO)

        # file log for azkaban file
        self.formatFile = '{"timestamp": "%(asctime)s", "hostaddr": "%(hostaddr)s", "name": "%(name)s", "process": "%(process)d", "processName": "%(processName)s", ' \
                          '"pythonfile": "%(pythonfile)s", "line": "%(line)d", "functionname": "%(functionname)s", "levelname": "%(levelname)s", ' \
                          '"appName": "%(appName)s", "jobName":"%(jobName)s", "message": %(message)s}'
        self.log_file = '/data/logs/access/' + appName+'/'+jobName
        self.initLogger()


    def initLogger(self):
        """在logger中添加日志句柄并返回，如果logger已有句柄，则直接返回
               我们这里添加两个句柄，一个输出日志到控制台，另一个输出到日志文件。
               两个句柄的日志级别不同，在配置文件中可设置。
               """
        if not self.logger.handlers:
            file_roll_handler = logging.handlers.TimedRotatingFileHandler(filename=self.log_file, when='MIDNIGHT',
                                                                          backupCount=0,
                                                                          delay=True,
                                                                          encoding='utf-8')
            file_roll_handler.suffix = '%Y-%m-%d.log'
            file_roll_handler.setLevel(logging.INFO)  # error以上的内容输出到文件里面
            file_roll_handler.setFormatter(logging.Formatter(self.formatFile))
            self.logger.addHandler(file_roll_handler)

        # return self.logger


    def buildJsonMsg(self, message, errstack=None):
        # return json.dumps(message, ensure_ascii=False)
        return message

    def info(self, stringwiheplaceholder, *args):
        if args is None or len(args)<=0:
            tmp2=stringwiheplaceholder
        else:
            tmp2 = stringwiheplaceholder.format(*args)
        tmp2 = self.buildJsonMsg(tmp2)
        # 对于太长的字符串进行截取
        if(len(tmp2) > 65535):
            tmp2 = tmp2[0:65535]
        extra = self.getCallerInfo()
        self.logger.info(tmp2,extra=extra)

    def warn(self, stringwiheplaceholder, *args):
        if args is None or len(args)<=0:
            tmp2=stringwiheplaceholder
        else:
            tmp2 = stringwiheplaceholder.format(*args)
        tmp2 = self.buildJsonMsg(tmp2)
        if (len(tmp2) > 1024):
            tmp2 = tmp2[0:1024]
        extra = self.getCallerInfo()
        self.logger.warning(tmp2,extra=extra)

    def error(self, stringwiheplaceholder, *args):
        if args is None or len(args)<=0:
            tmp2=stringwiheplaceholder
        else:
            tmp2 = stringwiheplaceholder.format(*args)
        # 獲取錯誤stack
        errstack = traceback.format_exc()
        tmp2=tmp2+"  ; "+errstack
        tmp2 = self.buildJsonMsg(tmp2)
        extra = self.getCallerInfo()
        self.logger.error(tmp2,extra=extra)

    def debug(self, stringwiheplaceholder, *args):
        if args is None or len(args)<=0:
            tmp2=stringwiheplaceholder
        else:
            tmp2 = stringwiheplaceholder.format(*args)
        tmp2 = self.buildJsonMsg(tmp2)
        if (len(tmp2) > 1024):
            tmp2 = tmp2[0:1024]
        extra = self.getCallerInfo()
        self.logger.debug(tmp2,extra=extra)

    def getCallerInfo(self):
        '''
        获取调用者信息
        :return:
        '''
        # 获取line和functionname
        pythonfile = None
        line = None
        functionname = None
        frame = sys._getframe(1)
        if frame:
            line = frame.f_back.f_lineno
            functionname = frame.f_back.f_code.co_name
            pythonfile = frame.f_back.f_code.co_filename

            names = []
            if pythonfile.__contains__('/'):
                names = pythonfile.split('/')
                if names and names.__len__() > 0:
                    pythonfile = names[-1]

        extra = {'hostaddr': self.hostip, 'appName': self.app, 'jobName': self.jobName,'pythonfile': pythonfile, 'functionname': functionname,'line': line}
        return extra